home *** CD-ROM | disk | FTP | other *** search
/ Mac100% 1998 November / MAC100-1998-11.ISO.7z / MAC100-1998-11.ISO / オンラインソフト定点観測 / ユーティリティ / Mops 3.2.sea / Mops 3.2 / Mops source / PPC source / pnuc3 < prev    next >
Text File  |  1998-06-13  |  23KB  |  861 lines

  1. ¥                    ===========================
  2. ¥                            APPLEEVENTS
  3. ¥                    ===========================
  4.  
  5. : AEHANDLER  ( ^AE ^AEReply RefCon -- )
  6.  
  7. ¥ Put at the start of an AppleEvent handler proc.  Pops the parms into
  8. ¥ the appropriate locations.
  9.  
  10. ;
  11.  
  12.     
  13. : GOTPARMS?  ( -- rc )
  14.  
  15. ¥ This can be called at the end of a handler, to check if we got all
  16. ¥ the parameters.
  17.  
  18. ;
  19.  
  20.  
  21. : ?RTNAEPMISSED  ( rc -- rc' )
  22.  
  23. ¥ This can be called after calling GotParms? to convert the return code
  24. ¥ from that word to the appropriate return code to return to the caller
  25. ¥ of the handler.  If GotParms? returns false, that means we missed
  26. ¥ a parm, so we return -1715.  If GotParms? returned anything non-zero,
  27. ¥ that means we got all the parms, so we return zero.
  28.  
  29.     IF  0  ELSE  -1715  THEN  ;
  30.  
  31.  
  32. ¥                    ========================
  33. ¥                         ERROR HANDLING
  34. ¥                    ========================
  35.  
  36. (*    This is unfortunately a bit complicated.  The basic mechanism is
  37.     the standard CATCH and THROW.  Apart from THROW, there are three
  38.     words which signal an error - ABORT, ABORT" and our Mops error
  39.     dump word DIE.
  40.     
  41.     The standard says that if CATCH and THROW are
  42.     implemented, ABORT throws a -1, and ABORT" throws a -2.  This
  43.     allows a throw handler to catch these and override the default
  44.     error action.
  45.     
  46.     If no throw handler is installed, the default action
  47.     occurs.  For this default action, we define DFLT_ABORT and DFLT_ERR
  48.     (I assume I didn't want to call it dflt-abort" since it doesn't take
  49.     an inline string - that was stored by ABORT".)
  50.  
  51.     We follow the same philosophy with DIE.  The error code passed to
  52.     DIE is simply THROWn (note we don't use any negative error code
  53.     for a non-ANSI Mops error), which allows a throw handler to intercept
  54.     it.  And we define DFLT_DIE to be executed if there's no throw handler,
  55.     which does our normal Mops error dump to the Mops window.
  56. *)
  57.  
  58.  
  59. forward QUIT
  60. forward (.stk)
  61. forward .objOrRA
  62. forward tstr
  63.  
  64.  
  65. 0        value    origCDP            ¥ set to the "normal" CDP if we're
  66.                                 ¥  temporarily in the execution buffer
  67.  
  68.  
  69. : TypeErrNum  ( err# -- )
  70.     instld?  ?EXIT
  71.     cr ." Error # "  dup .  space  tstr
  72. ;
  73.  
  74.  
  75. (*    SAVE_ERR ( addr len ^ed -- )
  76.     saves all the info needed for an error dump, for later use by the default
  77.     error handling routine which may be called after the stacks have been
  78.     reset.  This way, THROW can be called without our having to know if a
  79.     non-default error routine is installed or not.  ( addr len ) specifies
  80.     an error text string.  We may pass ( err# -1 ), in which case err# is a
  81.     Mops error number, whose text can be typed via TSTR.  For ABORT, which
  82.     has no error string, we pass ( 0 0 ).
  83.  
  84.     Our normal error word is DIE, which calls SAVE_ERR, then calls
  85.     ThrowWithInfo, the alternative to THROW.
  86. *)
  87.  
  88. : svStk  { start finish ^ed ¥ cnt -- ^ed' }
  89.     finish start -  2 >>  -> cnt        ¥ ## assumes 4-byte cells
  90.     cnt maxDump min  -> cnt
  91.     
  92.     cnt  ^ed !  1cell ++> ^ed
  93.     cnt FOR  start @  ^ed !  1cell ++> start  1cell ++> ^ed  NEXT
  94.     ^ed
  95. ;
  96.  
  97. : SAVE_ERR  { addr len ¥ ^ed -- }
  98.     ^errDump -> ^ed
  99.     len        ^ed !    1cell ++> ^ed
  100.     addr    ^ed !    1cell ++> ^ed        ¥ save the two parms
  101.     (^base)    ^ed !    1cell ++> ^ed        ¥ save ptr to current obj (-1 if none)
  102.     SP SP0 ^ed svStk  -> ^ed            ¥ save data stack
  103.     RP 20 +                                ¥ don't want to display the Rstack
  104.                                         ¥  cells with our error-handling calls
  105.                                         ¥  and saved regs
  106.     RP0 ^ed svStk  drop                    ¥ save return stack
  107. ;
  108.  
  109.  
  110. ¥ .ERR displays the error info saved by SAVE_ERR.  The value .stkLimit
  111. ¥  gives a maximum of stack cells dumped -- this can be used to keep
  112. ¥  info from scrolling off the screen.
  113.  
  114. big#    value    .stk_limit
  115.  
  116. : .ERR  { ¥ addr len ^obj ¥ ^ed -- }
  117.     ^errDump -> ^ed
  118.     ^ed @  -> len        1cell ++> ^ed
  119.     ^ed @  -> addr        1cell ++> ^ed
  120.  
  121.     setFwind    ¥ Redirected to abort word in installed applicns, so
  122.                 ¥  we don't try to type to the Mops window, which may
  123.                 ¥  well not exist.
  124.     5 beep  cr
  125.     len 0>
  126.     IF    addr len type  space    ¥ there's an error string
  127.     ELSE
  128.         len 0<
  129.         IF                        ¥ no error string - "addr" is
  130.                                 ¥  really an err number
  131.             addr 10 u>            ¥ err# 1-10 don't have messages - we
  132.                                 ¥  can use them for special things
  133.             IF  addr typeErrNum  THEN
  134.         THEN
  135.     THEN
  136.  
  137.     cr  src-start src-len type  cr    ¥ type error line
  138.     >in @ 1- spaces  & ^ emit  cr    ¥ and error position marker
  139.  
  140.     ^ed @   1cell ++> ^ed
  141.     -> ^obj
  142.     ^obj -1 <>
  143.     IF    ." Current object:  "
  144.         ^obj .objOrRA  cr
  145.     THEN
  146.  
  147.     ^ed @  cells -> len   1cell ++> ^ed
  148. ¥    .stk_limit 2dup > if nip else drop then  cells  -> len    
  149.     ." Stack:"
  150.     ^ed len over + false  (.stk)    len   ++> ^ed
  151.     ^ed @  cells -> len   1cell ++> ^ed
  152. ¥    .stk_limit min  cells  -> len    
  153.     ." Return stack:"
  154.     ^ed len over + true  (.stk)
  155.     big# -> .stk_limit
  156. ;
  157.  
  158. forward setup_cg
  159.  
  160. : dflt_abort
  161.     setup_cg            ¥ a bit drastic, but if the error is an index
  162.                         ¥  out of range on one of our register arrays,
  163.                         ¥  we'll just keep hitting the error!
  164.     origCDP IF  origCDP -> CDP  THEN
  165.     abortVec
  166.     SP0 4+ SP!  RP0 RP!  FSP0 16 +  FSP!
  167.     decimal
  168.     0  #TIB !  set_source  +curs
  169.     0 -> cstate
  170.     false -> local?
  171.     0 -> mod_seg#
  172.     QUIT
  173. ;
  174.  
  175. : dflt_abq
  176.     err_info_valid?
  177.     IF        3 -> .stk_limit  .err
  178.     ELSE    typeErrNum
  179.     THEN
  180.     dflt_abort
  181. ;
  182.  
  183.  
  184. forward        DFLT_DIE
  185.  
  186. : (ddie)
  187.     setFwind
  188.     0 -> (err#)            ¥ Clear error indicator from AppleEvents
  189.     dflt_abq  ;            ¥ Display error info and abort
  190.  
  191. :f dflt_die        (ddie)  ;f
  192.  
  193.  
  194. (*    CATCH  ( xt -- n )  EXECUTEs the xt.  If the executed word does a THROW,
  195.     n is the error code passed to THROW.  If it doesn't  do a THROW, n is
  196.     zero.  If it does a THROW, control doesn't return to CATCH, but to
  197.     whoever called CATCH.  See the Standard for a full description.
  198.     
  199.     We have to use assembly for setting this up, since we're manipulating
  200.     registers.
  201. *)
  202.  
  203. 0    value    THROW_HANDLER        ¥ holds the addr of the current throw handler
  204.                                 ¥  frame, or zero if none.
  205.  
  206. : frameErr
  207.     ." Return stack clobbered!"
  208.     dflt_abort
  209. ;
  210.  
  211.  
  212. : no_throw_handler ( n -- )        ¥ branched to from (THROW) if there's no
  213.                                 ¥  handler.  Takes the default action.
  214.  
  215.     errorVec                    ¥ set to error word in installed apps, so
  216.                                 ¥  we can bail out without Mops development
  217.                                 ¥  environment error handling
  218.  
  219.     dup -1 = IF  dflt_abort    THEN    ¥ -1: do default ABORT
  220.     dup -2 = IF  dflt_abq    THEN    ¥ -2: do default ABORT"
  221.     dflt_die
  222. ;
  223.  
  224.  
  225. :ppc_code  CATCH
  226.  
  227.     r0                    mflr,
  228.     r0        -4    rRP        stw,    ¥ save lr - our return addr
  229.     
  230.     r3        -16    rRP        stwu,    ¥ now save 1 cached stack cell (r3).  r4 is
  231.                                 ¥  xt for EXECUTE so we don't need to save it.
  232.                                 ¥ Note rRP must stay 8-byte aligned
  233.  
  234.     ' saves 2+            bl,
  235.     rRP        -48            addi,    ¥ now all our GPR locals (& keep rRP aligned)
  236.     ' fsaves 2+            bl,
  237.     rRP        -88            addi,    ¥ and all our FPR locals
  238.  
  239.     r0        $ 789A        li,
  240.     r0        -16    rRP        stwu,    ¥ create frame header and store marker
  241.     rSP        4    rRP        stw,    ¥ save SP at offs 4
  242.     r0        ' throw_handler 2+ @abs6 dicaddr
  243.                         lwz,
  244.     r0        8    rRP        stw,    ¥ and previous handler addr at offs 8
  245.     rRP        ' throw_handler 2+ @abs6 dicaddr
  246.                         stw,    ¥ and store RP (frame ptr) as new handler addr
  247.  
  248. ' execute 2+            bl,        ¥ execute the passed-in xt.  Note
  249.                                 ¥  this call only returns if THROW
  250.                                 ¥  isn't done.
  251.  
  252.     r0        0    rRP        lwz,    ¥ check our special marker is still
  253.     r0        $ 789A        cmpli,    ¥  on top of rtn stk
  254.  eq if,                            ¥ yep, all OK
  255.      r0        8    rRP        lwz,    ¥ get prev throw_handler from offs 8
  256.      r0    ' throw_handler 2+ @abs6  dicaddr
  257.                          stw,    ¥ restore previous throw_handler
  258.     
  259.      rRP        rRP    168        addi,    ¥ delete rest of frame - all regs OK already
  260.      r0        -4    rRP        lwz,    ¥ restore lr
  261.      r0                    mtlr,
  262. ¥     r3        -4    rSP        stwu,    ¥ we have 2 cached cells - push one off
  263. ¥     r3        r4            mr,
  264.      r4        r0    0        addi,    ¥ and return zero on top (means no error)
  265.                          blr,
  266.  then,
  267.         ' frameErr 2+    b,        ¥ rtn stk marker not there - call frameErr
  268.  
  269. ;ppc_code
  270.  
  271.  
  272. (*    THROW has two variants.  ThrowWithInfo is used by our normal error
  273.     word DIE, and also by ABORT", which both save the error info (including
  274.     a message string) before doing a normal throw.  This variant signals
  275.     that the saved error info is valid.  Our default error handler DFLT_DIE,
  276.     which is called if no throw handler has been installed, tests this flag
  277.     to decide whether to call .ERR to display the info.
  278.  
  279.     If THROW is called directly from code, it flags the error info invalid,
  280.     which prevents DFLT_DIE from calling .ERR and displaying spurious info.
  281. *)
  282.  
  283. :ppc_code (THROW)
  284.     r4        0    cmpli,            ¥ is THROW code nonzero
  285.  
  286. ne if,                            ¥ yes - we do the throw:
  287.      rX    ' throw_handler 2+ @abs6  dicaddr
  288.                          lwz,    ¥ restore previous throw_handler
  289.     rX        0    cmpli,            ¥ is there a throw handler?
  290.  
  291.  ne if,
  292.     r0        0    rX        lwz,    ¥ check our special marker is still
  293.     r0        $ 789A        cmpli,    ¥  on top of rtn stk
  294.   eq if,                        ¥ yep, all OK
  295.       rRP        rX            mr,        ¥ set RP to point to handler frame
  296.                                   ¥ Now we restore everything from the frame:
  297.       rSP        4    rRP        lwz,    ¥ rSP from offs 4
  298.        r0        8    rRP        lwz,
  299.      r0    ' throw_handler 2+ @abs6  dicaddr
  300.                          stw,    ¥ and previous throw_handler from offs 8
  301.      rRP        104            addi,
  302.      ' frestores 2+        bl,        ¥ restore FPR locals
  303.      rRP        48            addi,
  304.      ' restores 2+        bl,        ¥ and GPR locals
  305.      rRP        16            addi,    ¥ delete rest of frame
  306.  
  307.      r0        -4    rRP        lwz,    ¥ restore lr
  308.      r0                    mtlr,
  309.      r3        -16 rRP        lwz,    ¥ and cached stack cell (r3)
  310.                          blr,    ¥ and return to CATCH caller
  311.  
  312.   then,
  313.         ' frameErr 2+    b,        ¥ rtn stk marker not there - call frameErr
  314.  then,
  315.          ' no_throw_handler 2+    b,        ¥ no throw handler: take default action
  316. then,
  317.  
  318.     r4        r3            mr,        ¥ throw code zero - no error - just drop
  319.     r3        0    rSP        lwz,    ¥  the zero and return.
  320.     rSP        rSP    4        addi,
  321.                         blr,
  322. ;ppc_code
  323.  
  324.  
  325. :f THROW
  326.     false -> err_info_valid?  (throw)
  327. ;f
  328.  
  329. : THROW_WITH_INFO
  330.     true -> err_info_valid?  (throw)
  331. ;
  332.  
  333.  
  334. : ABORT
  335.     0 0 save_err  -1 throw  ;
  336.  
  337.  
  338. (*    ABORT" is immediate, so we've already defined it before CROSS
  339.     in qCond.  It gets the string parameter, then EVALUATEs do_abq
  340.     which we define here.  What we end up doing is in effect this:
  341.  
  342.         : ABORT"
  343.             postpone "
  344.             rot NIF  2drop  EXIT  THEN
  345.             save_err  -2 throw_with_info  ;        immediate
  346. *)
  347.  
  348. : do_abq
  349.     rot NIF  2drop  EXIT  THEN
  350.     save_err -2 throw_with_info  ;
  351.  
  352. 0    value    svErrNum
  353.  
  354. :f DIE
  355.     dup -> svErrNum  -1 save_err    ¥ -1 indicates to save_err that
  356.                                     ¥  this is an err#
  357.     svErrNum  throw_with_info
  358. ;f
  359.  
  360.  
  361. (* ****
  362.  
  363. ¥ THROW test:
  364.  
  365. : could-fail  key dup  & A = if  $ 1234 throw  then  ;
  366.  
  367. : doit    could-fail  nip nip nip  ;
  368.  
  369. : throwtest
  370. dbgr
  371.     1 2 3 ['] doit catch
  372. ¥ if there's no throw, the 1 2 3 will be dropped, and we'll get
  373. ¥  the typed key.  If throw is executed, we should get the 1 2 3
  374. ¥  and the error number $ 1234 on the stack.
  375.  
  376. dbgr dup
  377.     IF        ." Error was thrown" cr .s
  378.     ELSE    drop  ." The char was " emit cr
  379.     THEN  ;
  380.  
  381. **** *)
  382.  
  383.  
  384. : ?COMP
  385.     state  ?EXIT
  386.     -14 die  ;
  387.  
  388.  
  389. : ?STACK
  390.     depth dup 0<
  391.     IF  -4 die  THEN                    ¥ "stack underflow"
  392.     stack_size >= IF  -5 die  THEN        ¥ "stack overflow"
  393.     fdepth dup 0<
  394.     IF  -45 die  THEN                    ¥ "floating-point stack underflow"
  395.     fstack_size >= IF  -44 die  THEN    ¥ "floating-point stack overflow"
  396. ;
  397.  
  398. : ?EXEC
  399.     state  0EXIT
  400.     77 die  ;        ¥ "Execution state only"
  401.  
  402. : ?PAIRS
  403.     = ?EXIT
  404.     -22 die  ;        ¥ "Control structure mismatch"
  405.  
  406.  
  407. : ?DEFN
  408.     = ?EXIT
  409.     78 die  ;        ¥ "Unbalanced definition"
  410.  
  411. (*
  412.     (excep) is branched to from our exception handler in zObjInit.
  413.     We don't really know which regs held the top stack cells when the
  414.     exception occurred, so we just take as stab that it was r3 and r4.
  415.     The exception handler leaves the excep code in r5.  So we set up
  416.     (excep) with 3 named parms, which will be r3, r4 and r5.
  417.     
  418.     Here's Apple's defn of the exception codes:
  419.  
  420.     kUnknownException                = 0
  421.     kIllegalInstructionException     = 1
  422.     kTrapException                    = 2
  423.     kAccessException                = 3
  424.     kUnmappedMemoryException        = 4
  425.     kExcludedMemoryException        = 5
  426.     kReadOnlyMemoryException        = 6
  427.     kUnresolvablePageFaultException = 7
  428.     kPrivilegeViolationException     = 8
  429.     kTraceException                    = 9
  430.     kInstructionBreakpointException = 10
  431.     kDataBreakpointException        = 11
  432.     kIntegerException                = 12
  433.     kFloatingPointException            = 13
  434.     kStackOverflowException            = 14
  435.     kTerminationException            = 15
  436. *)
  437.  
  438. : (excep)  { x y ex# --  }
  439.     x y
  440.     ex# 210 +  die        ¥ we just assign all the message numbers appropriately
  441.                         ¥  so we don't have to do any other testing on the
  442.                         ¥  number.
  443. ;
  444.  
  445.  
  446.  
  447. ¥    ====================  ADDRESSING  =====================
  448.  
  449.  
  450. ¥ 16bits? ( n signed? -- n b )
  451. ¥  returns true if n will fit in 16 bits (signed or unsigned as requested).
  452.  
  453. : 16BITS?    ¥ ( n signed? -- n b )
  454.     IF    -32768 32767  within?
  455.     ELSE
  456.         dup 16 >> 0=
  457.     THEN
  458. ;
  459.  
  460. ¥ seg#>gpr# finds if the passed-in seg# corresponds to a currently
  461. ¥  set up base register.  If so, it returns the reg#.  If not, it
  462. ¥  returns zero.
  463.  
  464. : seg#>gpr#        ¥ ( seg# -- gpr# )
  465.  
  466.     CASE[  8    ]=>        mainCode_reg  EXIT
  467.         [  9    ]=>        mainData_reg  EXIT
  468.     DEFAULT=>
  469.     ]CASE
  470.  
  471.   ( seg# )
  472.   ¥  here we don't use case[ since the test values aren't constant.
  473.   
  474.       dup  mod_seg#        = IF  drop  modCode_reg  EXIT  THEN
  475.       dup  mod_seg# 1+    = IF  drop  modData_reg  EXIT  THEN
  476.       dup  comp_seg#        = IF  drop    modCode_reg  EXIT  THEN
  477.            comp_seg# 1+    = IF        modData_reg  EXIT  THEN
  478.  
  479.       0            ¥ failed -  return zero
  480. ;
  481.  
  482.  
  483. ¥ B&D takes the passed-in address and converts it to gpr# and displacement.
  484. ¥ We also store the appropriate segment # in seg#_to_use, in case we're
  485. ¥  generating a relocatable addr.
  486.  
  487. 0    value    seg#_to_use
  488.  
  489. : (B&D) { theAddr ¥ seg# displ gpr# -- gpr# displ' }
  490.  
  491.     0 -> seg#_to_use
  492.     theAddr addr>S&D  -> displ -> seg#    ¥ both will be zero if theAddr is 
  493.                                         ¥  not in any segment
  494.                                             
  495.     seg# seg#>gpr#  -> gpr#                ¥ will be zero if we didn't get a reg
  496.  
  497.     gpr# mainCode_reg =
  498.     IF
  499.         displ code_start + nuc_code_start -  half_displ_range -  -> displ
  500.         displ true 16bits? nip
  501.         NIF                ¥ displ doesn't fit in 16 bits, but we might have
  502.                         ¥  a const data pointer which we can use...
  503.             CD_gpr#
  504.             IF            ¥ if we've set it, we use it, since this will
  505.                         ¥  just about always give us a displ which fits
  506.                         ¥  in 16 bits
  507. ¥ dbgr const_data_start -> displ
  508.                 CD_gpr# -> gpr#  theAddr CD_gpr_loc -  -> displ
  509.             THEN
  510.         THEN
  511.  
  512.         gpr# displ  EXIT
  513.     THEN
  514.     
  515.     gpr# mainData_reg =
  516.     IF    mainData_reg
  517.         displ  data_start +  nuc_data_start -  half_displ_range -
  518.         EXIT
  519.     THEN
  520.  
  521.     gpr#
  522.     IF    seg# -> seg#_to_use
  523.         gpr#
  524.         displ half_displ_range -
  525.     ELSE            ¥ theAddr wasn't in range of any reg - return two zeros
  526.         0  0
  527.     THEN
  528. ;
  529.  
  530.  
  531. : B&D  { theAddr -- reg# displ }
  532.     theAddr (b&d) over
  533.     NIF     cr  theAddr .h ."   is an out-of-range addr!" 1 die  THEN
  534. ;
  535.  
  536.  
  537. ¥ @B&D fetches a relocatable addr and returns the "real" base
  538. ¥ gpr# and displacement.  This is used for going from the code
  539. ¥  area to the data area, for values etc.
  540.  
  541. : @B&D { addr ¥ relocAddr seg# displ gpr# -- gpr# displ' }
  542.     addr @  -> relocAddr
  543.     relocAddr  $ ffffff and  -> displ
  544.     relocAddr  24 >>  -> seg#
  545.  
  546.     seg# seg#>gpr#  -> gpr#
  547.  
  548.     gpr# mainCode_reg =
  549.     IF    mainCode_reg
  550.         displ code_start + nuc_code_start -  half_displ_range -
  551.         EXIT
  552.     THEN
  553.     
  554.     gpr# mainData_reg =
  555.     IF    mainData_reg
  556.         displ  data_start +  nuc_data_start -  half_displ_range -
  557.         EXIT
  558.     THEN
  559.  
  560.     gpr#
  561.     IF    gpr#  displ half_displ_range -
  562.                     ¥ machine instrns use a signed displ, so we
  563.                     ¥  point base regs 32k above the seg start
  564.                                         
  565.     ELSE            ¥ seg# didn't refer to a loaded reg, or was just garbage
  566.         70 die        ¥ " not a reloc addr"
  567.     THEN
  568. ;
  569.  
  570.  
  571. : RELOC!  { theAddr dest -- }
  572. ¥ theAddr $ 1000 u< if dbgr then
  573.     theAddr addr>S&D
  574.     $ ffffff and  swap  24 <<  or
  575.     dest !
  576. ;
  577.  
  578.  
  579.  
  580. ¥                ================================
  581. ¥                CONVERSION BETWEEN RELATIVE AND
  582. ¥                     ABSOLUTE ADDRESSES
  583. ¥                ================================
  584.  
  585. ¥ Note: @abs is already defined in Setup, since we needed it earlier.
  586.  
  587.  
  588. : DISPLACE   ( addr -- addr' )  inline{ dup @ dup if + else nip then}  ;
  589. : WDISPLACE  ( addr -- addr' )  inline{ dup w@x dup if + else nip then}  ;
  590.  
  591. : DISPL!  { src dst -- }
  592. ¥ Stores the source address as a relative address at the destination.
  593.     src dst -  dst !  ;
  594.  
  595. : WDISPL!  { src dst -- }
  596. ¥ Stores the source address as a short relative address at the destination
  597. ¥ (it is relative to the destination).
  598.     src dst -  dst w!  ;
  599.  
  600.  
  601. : reloc,        DP    reloc!  4 ++> DP   ;
  602. : relocCode,    CDP reloc!  4 ++> CDP  ;
  603. : displCode,    CDP displ!    4 ++> CDP  ;
  604.  
  605.  
  606.  
  607. ¥            =====================================
  608. ¥                    DICTIONARY OPERATIONS
  609. ¥            =====================================
  610.  
  611. forward defined?        ¥ needed by FORGET.  Defined in pnuc4.
  612.  
  613.  
  614. (* ********************************************************************
  615. Patches_done is called on the 68k after any new instructions have been
  616. stored, or patches have been done, and before the instructions are
  617. executed.  It flushes the instruction cache if necessary.
  618.  
  619. On some PPC models there's also a separate icache and dcache, so we have
  620. to do the same sort of thing.  We use a piece of code posted on usenet
  621. by Tim Olson of Apple.  It's helpful to know the addr and len of the area
  622. affected, since it would waste a lot of time to flush the caches for
  623. unaffected addresses.  So we define a word with a new name which takes
  624. an addr and len.
  625.  
  626.  
  627. First, Tim's post:
  628.  
  629. From: tim@apple.com (Tim Olson)
  630.  
  631. ....
  632.  
  633. Correct.  The PowerPC architecture does not enforce coherency of
  634. instruction caches.  To generate code "on the fly", one must explicitly
  635. make the instruction cache coherent with memory by performing the
  636. following sequence of operations:
  637.  
  638.   1) DCBST or DCBF, and an ICBI on each cache block 
  639.      that contains the generated code -- this pushes
  640.      the modified code out to memory, where it can be
  641.      fetched as instructions, and invalidates any
  642.      "stale" instruction cache blocks in that range
  643.      which may still be found in the instruction cache.
  644.  
  645.   2) SYNC instruction.  This forces all of the operations
  646.      above to memory before continuing on to possibly start
  647.      executing the generated code.
  648.  
  649.   3) ISYNC instruction (or other context-synchronizing
  650.      operation).  This forces any prefetched instructions
  651.      to be discarded and refetched.
  652.  
  653. Even though some implementations may not require all of these
  654. operations (e.g. the 601), this is what is required by the architecture
  655. in order for the code to work on all implementations.
  656.  
  657. A routine to do this could be something like:
  658.  
  659. ; makeDataExecutable -- enforce coherency of instruction and
  660. ;     data caches before executing generated code
  661. ;     r3 = beginning address of generated code
  662. ;     r4 = size of generated code (in bytes)
  663. ;     assumes cache block granule is 32 bytes
  664.  
  665. makeDataExecutable:
  666.       addi    r4, r4, 31
  667.       srwi    r4, r4, 5       ;convert to cache blocks to flush
  668.       mtctr   r4
  669.       li      r4, 0
  670.  
  671. loop:
  672.       dcbf    r3, r4          ;flush data cache block to mem
  673.       icbi    r3, r4          ;invalidate block in icache
  674.       addi    r4, r4, 32
  675.       bdnz    loop
  676.  
  677.       sync                    ;force mem transactions to complete
  678.       isync                   ;flush prefetch
  679.       blr                     ;return to calling routine
  680.  
  681.  
  682.  
  683. -- Tim Olson
  684. Apple Computer, Inc.
  685. (tim@apple.com)
  686.  
  687. ***************************************************************** *)
  688.  
  689.  
  690. :ppc_code  ()  ( addr len -- )
  691.  
  692. ¥ On entry (as per our stack convention for code words):
  693. ¥ r3 = addr
  694. ¥ r4 = len
  695.  
  696.     r4        0            cmpli,
  697. ne if,                                ¥ do nothing if len is zero
  698.  
  699.     r4        r4    31        addi,
  700.     r4        r4 27 5 31    rlwinm,        ¥ shift right 5 - #cache blocks to flush
  701.     r4                    mtctr,
  702.     r4        0            li,
  703. CDPx                                ¥ start of loop
  704.     r3        r4            dcbf,        ¥ flush data cache block to mem
  705.     r3        r4            icbi,        ¥ invalidate block in icache
  706.     r4        r4    32        addi,
  707.                 dnz        bc,            ¥ loop
  708.                         sync,        ¥ force mem transactions to complete
  709.                         isync,        ¥ flush prefetch
  710. then,
  711.     r4        0    rSP        lwz,        ¥ pop the 2 stack cells
  712.     r3        4    rSP        lwz,
  713.     rSP        rSP    8        addi,
  714.                         blr,        ¥ and return
  715. ;ppc_code
  716.  
  717.  
  718. :f FIX_CACHES  { addr len -- }
  719.     len 0EXIT
  720.     addr len  %_MakeDataExecutable
  721. ;f
  722.  
  723.  
  724. ¥ : ALLOT        ( n -- )    ++> DP  ;
  725. : RESERVE    ( n -- )    DP over 0 fill  ++> DP  ;
  726.  
  727. : ,  ( n -- )    DP !    4 ++> DP  ;
  728. : W, ( n -- )    DP w!    2 ++> DP  ;
  729. : C, ( n -- )    DP c!    1 ++> DP  ;
  730.  
  731. : N, ( addr len -- )    >r  DP r@ cmove  r> allot  ;
  732.  
  733. : DISPL,  ( src -- )
  734.     DP -  ,  ;
  735.  
  736.  
  737. : code,        CDP !    4 ++> CDP  ;
  738. : codeW,    CDP w!    2 ++> CDP  ;
  739. : codeC,    CDP c!    1 ++> CDP  ;
  740.  
  741. : codeN,  ( addr len -- )
  742.     tuck
  743.     CDP swap cmove
  744.     ++> CDP
  745. ;
  746.  
  747. : ALIGN4
  748.     DP
  749.     4 reserve            ¥ just to ensure pad bytes are zero
  750.     3 +  $ fffffffc and  -> DP
  751. ;
  752.  
  753. : ALIGN8
  754.     DP
  755.     8 reserve
  756.     7 +  $ fffffff8 and  -> DP
  757. ;
  758.  
  759. : ALIGN        align4  ;
  760. : ALIGN-DP    align4  ;
  761.  
  762. : #ALIGN    inline{ 3+ -4 and}  ;        ¥ a synonym for #align4 (in pnuc1)
  763.                                         ¥  - on the PPC our default alignment is
  764.                                         ¥  4 byte
  765. : ALIGNED    inline{ 3+ -4 and}  ;        ¥ ANSI - same as #align4 on PPC
  766. : #ALIGN2    inline{ 1+ -2 and}  ;
  767.  
  768. ¥ #align4 is in pnuc1, since we need it early
  769.  
  770. : #ALIGN8     7 +  $ fffffff8 and  ;
  771. : #ALIGN16    15 +  $ fffffff0 and  ;
  772.  
  773. : #OFF-ALIGN    ¥ ( n -- n' )  Aligns to the 2-byte boundary between
  774.                 ¥  adjacent 4-byte boundaries.
  775.     5 + $ fffffffc and 2-  ;
  776.  
  777.  
  778.  
  779. : code_allot    ++> CDP  ;
  780. : code_reserve    CDP over erase  ++> CDP  ;
  781. : code_align    CDP 4 erase  CDP #align4  -> CDP  ;
  782.  
  783.  
  784.  
  785. ¥ FORGET isn't really adequate on the PPC, since it can't handle the
  786. ¥  data area or syscall_chain etc.  But I'll keep it for backward
  787. ¥  compatibility, and it can be called by MARKER anyway to do the
  788. ¥  part of the job that it can.
  789.  
  790.  
  791. ¥ Trim  ( lfa -- new_latest )  is called by (forget).
  792.  
  793. : trim  { lfa ¥ cxt nxt link new_lfa -- new_latest }
  794.  
  795.     0 -> new_lfa
  796.     #threads FOR
  797.         context  i  2 <<  +  dup -> cxt        ¥ addr of this context entry
  798.         displace
  799.         BEGIN    dup lfa u>=
  800.         WHILE    displace
  801.         REPEAT
  802.     ¥ new context value for this thread
  803.         dup new_lfa umax -> new_lfa
  804.         cxt displ!
  805.     NEXT
  806.     new_lfa l>name        ¥ new link field -> new name field, which
  807.                         ¥  will become the new LATEST
  808. ;
  809.  
  810.  
  811. : (FORGET)  { lfa -- }
  812.     lfa fence u< IF  -15 die  THEN        ¥ "invalid FORGET"
  813.     lfa trim  -> latest
  814.  
  815. ¥ now we reset CDP to lfa.  First we call fix_caches on the range
  816. ¥  we're wiping out, since it doesn't exist any more, and we're
  817. ¥  a bit paranoid.
  818.  
  819.     lfa                    ¥ where we're wiping out from
  820.     CDP lfa -            ¥ # bytes we're wiping out
  821.     fix_caches
  822.     lfa -> CDP            ¥ reset CDP to new spot
  823. ;
  824.  
  825.  
  826. : FORGET
  827.     defined? ?notfound        ¥ i.e. tick - but we can't define that yet since
  828.                             ¥  we still need the 68k tick.  It's in qpCond.
  829.     >link (forget)  ;
  830.  
  831.  
  832.  
  833. ¥        =============  Module-related words  ===================
  834.  
  835. (*    There are a few module-related words which we use in the class
  836.     code.  Holdmod is forward defined, and resolved in zModules.  Of
  837.     course it should never need to be executed before zModules is loaded!
  838.     
  839.     unholdMod and ?unholdMod don't release the module as they do on
  840.     the 68k - once a module is loaded it stays put.  So all these words
  841.     have to do here is clear heldMod.
  842. *)
  843.  
  844. forward  holdMod
  845.  
  846. : unholdMod        0 -> heldMod  ;
  847. : ?unholdMod    0 -> heldMod  ;
  848.  
  849.  
  850. : ?>classInMod  ( ^class -- ^class' )
  851. ¥    0 -> seg#_accessed    ¥ leave zero if we don't go into a module
  852.     dup 2- w@            ¥ class handler code
  853.     $ BC2D =
  854.     IF    holdMod            ¥ if class_in_mod_h, replaces ^class with the
  855.                         ¥  xt of the class in the mod, and holds it.
  856.     THEN
  857. ;
  858.  
  859.  
  860. endload
  861.